package com.ruibang.glass.material.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruibang.glass.common.constants.RedisKey;
import com.ruibang.glass.common.domain.camunda.BpmProcessInstanceCreate;
import com.ruibang.glass.common.domain.camunda.BpmProcessInstanceStatus;
import com.ruibang.glass.material.constant.Constants;
import com.ruibang.glass.material.constant.MaterialErrorCode;
import com.ruibang.glass.material.constant.MaterialStatusCode;
import com.ruibang.glass.material.domain.req.AllocationManagementReq;
import com.ruibang.glass.material.entity.*;
import com.ruibang.glass.material.feign.CamundaApi;
import com.ruibang.glass.material.mapper.GMaterialWarehouseInfoMapper;
import com.ruibang.glass.material.mapper.MaterialAllocationItemMapper;
import com.ruibang.glass.material.mapper.MaterialAllocationManagementMapper;
import com.ruibang.glass.material.service.GMaterialALLInventoryManagementService;
import com.ruibang.glass.material.service.GMaterialManagementService;
import com.ruibang.glass.material.service.MaterialAllocationManagementService;

import com.teaming.cloud.framework2.autoconfigure.redis.RedisSingleService;
import com.teaming.cloud.framework2.common.exception.ServiceException;
import com.teaming.cloud.framework2.common.model.ResultBody;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 调拨管理 服务实现类
 * </p>
 *
 * @author mameng
 * @since 2024-04-15
 */
@Service
public class MaterialAllocationManagementServiceImpl extends ServiceImpl<MaterialAllocationManagementMapper, MaterialAllocationManagement> implements MaterialAllocationManagementService {

    @Autowired
    private RedisSingleService redisService;
    @Autowired
    private CommonService commonService;

    @Autowired
    private CamundaApi camundaApi;

    @Autowired
    private GMaterialALLInventoryManagementService materialALLInventoryManagementService;

    @Autowired
    private GMaterialManagementService materialManagementService;

    /**
     * 调拨管理 服务实现类
     *
     * @param
     * @return
     */

    @Override
    public IPage<MaterialAllocationManagement> getPage(AllocationManagementReq allocationManagementReq) {
        LambdaQueryWrapper<MaterialAllocationManagement> queryWrapper = Wrappers.<MaterialAllocationManagement>lambdaQuery();
        if (StringUtils.isNotBlank(allocationManagementReq.getAllocationNumber())) {
            queryWrapper.like(MaterialAllocationManagement::getAllocationNumber, allocationManagementReq.getAllocationNumber());
        }
        if (StringUtils.isNotBlank(allocationManagementReq.getApplyUser())) {
            queryWrapper.like(MaterialAllocationManagement::getApplyUser, allocationManagementReq.getApplyUser());
        }
        if (StringUtils.isNotBlank(allocationManagementReq.getInPlant())) {
            queryWrapper.like(MaterialAllocationManagement::getInPlant, allocationManagementReq.getInPlant());
        }
        if (StringUtils.isNotBlank(allocationManagementReq.getInWarehouse())) {
            queryWrapper.like(MaterialAllocationManagement::getInWarehouse, allocationManagementReq.getInWarehouse());
        }
        if (StringUtils.isNotBlank(allocationManagementReq.getLeavePlant())) {
            queryWrapper.like(MaterialAllocationManagement::getLeavePlant, allocationManagementReq.getLeavePlant());
        }
        if (StringUtils.isNotBlank(allocationManagementReq.getLeaveWarehouse())) {
            queryWrapper.like(MaterialAllocationManagement::getLeaveWarehouse, allocationManagementReq.getLeaveWarehouse());
        }
        if (StringUtils.isNotBlank(allocationManagementReq.getReceiveUser())) {
            queryWrapper.like(MaterialAllocationManagement::getReceiveUser, allocationManagementReq.getReceiveUser());
        }
        Page<MaterialAllocationManagement> materialWarehouseInfoPage = baseMapper.selectPage(new Page<>(allocationManagementReq.getPageNo(), allocationManagementReq.getPageSize()),
                queryWrapper.orderByDesc(MaterialAllocationManagement::getCreateTime)
        );

        if (CollectionUtils.isEmpty(materialWarehouseInfoPage.getRecords())) {
            return materialWarehouseInfoPage;
        }
        Map<Object, Object> userMap = redisService.hmget(RedisKey.USER_GROUP_TYPE);
        List<String> businessKeys = materialWarehouseInfoPage.getRecords().stream().map(MaterialAllocationManagement::getId).collect(Collectors.toList());
        Map<String, BpmProcessInstanceStatus> processMap = null;
        //获取业务流程状态
        ResultBody<List<BpmProcessInstanceStatus>> resultBody = camundaApi.queryProcessInstanceStatus(businessKeys);
        if (resultBody != null && CollectionUtils.isNotEmpty(resultBody.getData())) {
            processMap = resultBody.getData().stream().collect(Collectors.toMap(bp -> bp.getBusinessKey(), bp -> bp, (bp1, bp2) -> bp1));
        }
        if (processMap != null) {
            for (MaterialAllocationManagement materialAllocationManagement : materialWarehouseInfoPage.getRecords()) {
                if (processMap.get(materialAllocationManagement.getId()) != null) {
                    materialAllocationManagement.setStatus(String.valueOf(processMap.get(materialAllocationManagement.getId()).getStatus()));
                    materialAllocationManagement.setProcessId(processMap.get(materialAllocationManagement.getId()).getProcessInstanceId());
//                    materialAllocationManagement.setApproveStatus(processMap.get(materialAllocationManagement.getId()).getResult());
                    materialAllocationManagement.setNodeName(processMap.get(materialAllocationManagement.getId()).getNodeName());
                    String userId = processMap.get(materialAllocationManagement.getId()).getUserId();
                    if (StringUtils.isNotEmpty(userId) && !StringUtils.equals(userId, "null")) {
                        materialAllocationManagement.setApproveUser(userMap.get(userId).toString());
                        materialAllocationManagement.setApproveUserId(userId);
                    }
                }
            }
        }
        return materialWarehouseInfoPage;
    }

    @Autowired
    private MaterialAllocationItemMapper materialAllocationItemMapper;

    /**
     * 流程发起
     *
     * @param
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addMaterialAllocationManagement(MaterialAllocationManagement materialAllocationManagement) {
        if (StringUtils.equals(materialAllocationManagement.getLeaveWarehouseId(), materialAllocationManagement.getInWarehouseId())
                && StringUtils.equals(materialAllocationManagement.getLeavePlantId(), materialAllocationManagement.getInPlantId())) {
            throw new ServiceException(MaterialErrorCode.WAREHOUSE_ID_SAME.getCode(), MaterialErrorCode.WAREHOUSE_ID_SAME.getMsg());
        }
        if (CollectionUtils.isEmpty(materialAllocationManagement.getMaterialAllocationItemList())) {
            throw new ServiceException(MaterialErrorCode.ALLOCATION_NO_PRODUCT.getCode(), MaterialErrorCode.ALLOCATION_NO_PRODUCT.getMsg());
        }
        baseMapper.insert(materialAllocationManagement);
        for (MaterialAllocationItem materialAllocationItem : materialAllocationManagement.getMaterialAllocationItemList()) {
            materialAllocationItem.setAllocationId(materialAllocationManagement.getId());
            materialAllocationItemMapper.insert(materialAllocationItem);
        }
        BpmProcessInstanceCreate instanceCreate = new BpmProcessInstanceCreate();
        instanceCreate.setBusinessKey(materialAllocationManagement.getId());
        instanceCreate.setMenuId(materialAllocationManagement.getMenuId());
        //发起流程
        if (StringUtils.isNotBlank(materialAllocationManagement.getApplyUserId())) {
            Map<String, Object> variables = new HashMap<>();
            variables.put(com.ruibang.glass.common.constants.Constants.PROCESS_INSTANCE_STARTER_USER_ID, materialAllocationManagement.getApplyUserId());
            variables.put(com.ruibang.glass.common.constants.Constants.PROCESS_INSTANCE_BUSINESS_KEY, materialAllocationManagement.getId());
            variables.put(com.ruibang.glass.common.constants.Constants.PROCESS_INSTANCE_MENU_ID, materialAllocationManagement.getMenuId());
            instanceCreate.setVariables(variables);
        }
        commonService.startProcess(instanceCreate);
    }

    @Autowired
    private GMaterialWarehouseInfoMapper materialWarehouseInfoMapper;

    /**
     * 计算库存
     *
     * @param
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateItemHouse(MaterialAllocationManagement materialAllocationManagement) {
        //检验流程是否结束
        String approveStatus = getApproveStatus(materialAllocationManagement.getId());
        if (!StringUtils.equals(approveStatus, Constants.TWO_STR)) {
            return;
        }
        MaterialAllocationManagement allocationManagement = baseMapper.selectById(materialAllocationManagement.getId());
        List<MaterialAllocationItem> materialAllocationItems = materialAllocationItemMapper.selectList(Wrappers.<MaterialAllocationItem>lambdaQuery().eq(MaterialAllocationItem::getAllocationId, materialAllocationManagement.getId()));
        if (CollectionUtils.isEmpty(materialAllocationItems)) {
            throw new ServiceException(MaterialErrorCode.ALLOCATION_NO_PRODUCT.getCode(), MaterialErrorCode.ALLOCATION_NO_PRODUCT.getMsg());
        }
        for (MaterialAllocationItem materialAllocationItem : materialAllocationItems) {
            if (StringUtils.isBlank(materialAllocationItem.getItemCode())) {
                throw new ServiceException(MaterialStatusCode.NO_PRODUCT_CODE.getCode(), MaterialStatusCode.NO_PRODUCT_CODE.getMsg());
            }
            MaterialALLInventoryManagement one = materialALLInventoryManagementService.getOne(Wrappers.<MaterialALLInventoryManagement>lambdaQuery()
                    .eq(MaterialALLInventoryManagement::getMaterialName, materialAllocationItem.getItemName())
                    .eq(MaterialALLInventoryManagement::getMaterialCode, materialAllocationItem.getItemCode())
                    .eq(MaterialALLInventoryManagement::getWareHouseId, materialAllocationManagement.getInWarehouse())
                    .last("limit 1"));
            MaterialALLInventoryManagement outOne = materialALLInventoryManagementService.getOne(Wrappers.<MaterialALLInventoryManagement>lambdaQuery()
                    .eq(MaterialALLInventoryManagement::getMaterialName, materialAllocationItem.getItemName())
                    .eq(MaterialALLInventoryManagement::getMaterialCode, materialAllocationItem.getItemCode())
                    .last("limit 1"));
            if (materialAllocationItem.getQuantity() == null) {
                throw new ServiceException(MaterialStatusCode.WARE_HOUSE_QUALITY_LESS_USE_QUALITY.getCode(), MaterialStatusCode.WARE_HOUSE_QUALITY_LESS_USE_QUALITY.getMsg());
            }
            if (outOne == null) {
                throw new ServiceException(MaterialStatusCode.NO_PRODUCT_CODE.getCode(), MaterialStatusCode.NO_PRODUCT_CODE.getMsg());
            }
            Integer quality = outOne.getStockQuantity();
            Integer quantity = materialAllocationItem.getQuantity();
            if (quality < quantity) {
                throw new ServiceException(MaterialStatusCode.WAREHOUSE_LESS_IN_WAREHOUSE.getCode(), MaterialStatusCode.WAREHOUSE_LESS_IN_WAREHOUSE.getMsg());
            }
            Integer count = quality - quantity;
            outOne.setStockQuantity(count);
            materialALLInventoryManagementService.updateById(outOne);
            MaterialWarehouseInfo materialWarehouseInfo = materialWarehouseInfoMapper.selectById(materialAllocationManagement.getLeaveWarehouseId());
            MaterialManagement materialManagement = materialManagementService.getOne(Wrappers.<MaterialManagement>lambdaQuery()
                    .eq(MaterialManagement::getItemName, materialAllocationItem.getItemName())
                    .eq(MaterialManagement::getMaterialCode, materialAllocationItem.getItemCode())
                    .last("limit 1"));
            if (one == null) {
                MaterialALLInventoryManagement materialALLInventoryManagement = new MaterialALLInventoryManagement();
                materialALLInventoryManagement.setMaterialName(outOne.getMaterialName());
                materialALLInventoryManagement.setStockQuantity(materialAllocationItem.getQuantity());
                materialALLInventoryManagement.setMaterialId(materialAllocationManagement.getId());
                materialALLInventoryManagement.setSpecification(materialManagement.getSpecificationModel());
                materialALLInventoryManagement.setBarcodeNumber(materialManagement.getBarcode());
                materialALLInventoryManagement.setBatchNumber(outOne.getBatchNumber());
                materialALLInventoryManagement.setStockQuantity(materialAllocationItem.getQuantity());
                materialALLInventoryManagement.setUnit(materialManagement.getUnit());
                materialALLInventoryManagement.setStorageLocation(outOne.getStorageLocation());
                materialALLInventoryManagement.setProductionDate(outOne.getProductionDate());
                materialALLInventoryManagement.setExpirationDate(outOne.getExpirationDate());
                materialALLInventoryManagement.setInventoryDate(LocalDateTime.now());
                materialALLInventoryManagement.setWareHouseCode(materialWarehouseInfo.getWarehouseCode());
                materialALLInventoryManagement.setWareHouseName(materialWarehouseInfo.getWarehouseName());
                materialALLInventoryManagement.setWareHouseId(materialWarehouseInfo.getId());
                materialALLInventoryManagementService.save(materialALLInventoryManagement);
            } else {
                if (one.getStockQuantity() == null) {
                    one.setStockQuantity(materialAllocationManagement.getQuantity());
                    materialALLInventoryManagementService.updateById(one);
                }
            }
        }
        allocationManagement.setFinishDate(LocalDateTime.now());
        allocationManagement.setReceiveStatus(Constants.TWO_STR);
        baseMapper.updateById(allocationManagement);
    }

    @Override
    public MaterialAllocationManagement getMaterialAllocationManagement(String id) {
        MaterialAllocationManagement materialAllocationManagement = baseMapper.selectById(id);
        List<MaterialAllocationItem> materialAllocationItems = materialAllocationItemMapper.selectList(Wrappers.<MaterialAllocationItem>lambdaQuery().eq(MaterialAllocationItem::getAllocationId, id));
        materialAllocationManagement.setMaterialAllocationItemList(materialAllocationItems);
        return materialAllocationManagement;
    }

    public String getApproveStatus(String id) {
        List<String> ids = new ArrayList<>();
        ids.add(id);
        ResultBody<List<BpmProcessInstanceStatus>> resultBody = camundaApi.queryProcessInstanceStatus(ids);
        Map<String, String> approveStatusMap = null;
        if (resultBody != null && CollectionUtils.isNotEmpty(resultBody.getData())) {
            approveStatusMap = resultBody.getData().stream().collect(Collectors.toMap(BpmProcessInstanceStatus::getBusinessKey, BpmProcessInstanceStatus::getResult, (s1, s2) -> s1));
        }
        if (approveStatusMap.get(id) != null) {
            return approveStatusMap.get(id);
        }
        return "";
    }
}
